/* SPDX-License-Identifier: GPL-2.0 */
#ifndef SEMINIX_MM_H
#define SEMINIX_MM_H

#include <seminix/kernel.h>
#include <seminix/string.h>
#include <seminix/mm_types.h>
#include <seminix/gfp.h>
#include <seminix/mmzone.h>
#include <seminix/sched.h>
#include <asm/memory.h>

struct mmu_gather;

/* 内核符号地址转换为线性地址 */
#ifndef lm_alias
#define lm_alias(x)	__va(__pa_symbol(x))
#endif

/* 释放当前 memblock 所有内存到 buddy 系统 */
extern void free_area_init_nodes(void);

/*
 * 取消内核域指定范围映射, 用于 free_initmem 释放 __init 后取消预留内核映射
 */
extern void unmap_kernel_range(unsigned long addr, unsigned long size);

/*
 * 将所有 __init* 段释放到 buddy 系统中
 */
extern void free_initmem(void);

/* 打印所有内存信息 */
extern void mem_print_memory_info(void);








void print_vma_addr(char *prefix, unsigned long rip);











extern struct mm_struct *mm_struct_create(void);



extern void mm_set_task(struct mm_struct *mm, struct task_struct *tsk);
extern void mm_clear_task(struct task_struct *tsk);


extern int expand_stack(struct vm_area_struct *vma, unsigned long address);








/* handle page fault */
typedef int vm_fault_t;

#define VM_FAULT_OOM	        0x0001
#define VM_FAULT_SIGBUS	        0x0002
#define VM_FAULT_WRITE          0x0004
#define VM_FAULT_HWPOISON       0x0008	/* Hit poisoned small page */
#define VM_FAULT_HWPOISON_LARGE 0x0010  /* Hit poisoned large page. Index encoded in upper bits */
#define VM_FAULT_SIGSEGV        0x0020

#define VM_FAULT_NOPAGE	        0x0100

#define VM_FAULT_ERROR	(VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \
             VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)

#define VM_FAULT_SET_HINDEX(x) ((x) << 12)
#define VM_FAULT_GET_HINDEX(x) (((x) >> 12) & 0x12)

enum fault_flags {
    /* 故障来源于读访问 */
    FAULT_FLAG_READ         = 1 << 0,
    /* 故障来源于写访问 */
    FAULT_FLAG_WRITE        = 1 << 1,
    /* 故障任务在 SIGKILL 可 kill 区域 */
    FAULT_FLAG_KILLABLE     = 1 << 2,
    /* 故障来源于取指令 */
    FAULT_FLAG_INSTRUCTION  = 1 << 3,
    /* 故障来源于用户空间 */
    FAULT_FLAG_USER         = 1 << 4,
};

struct vm_fault {
    struct vm_area_struct *vma;	/* Target VMA */
    enum fault_flags flags;		/* FAULT_FLAG_xxx flags */
    unsigned long address;		/* Faulting virtual address */
    pgd_t *pgd;                 /* Pointer to pgd entry matching the 'address' */
    p4d_t *p4d;                 /* Pointer to p4d entry matching the 'address' */
    pud_t *pud;			        /* Pointer to pud entry matching the 'address' */
    pmd_t *pmd;			        /* Pointer to pmd entry matching the 'address' */
    pte_t *pte;			        /* Pointer to pte entry matching the 'address' */
    pgprot_t prot;

    bool is_hugetlb;
    int page_shift;
    int index;
    struct page *page;
};

/*
 * Can be called by the pagefault handler when it gets a VM_FAULT_OOM.
 */
extern void pagefault_out_of_memory(void);
extern vm_fault_t handle_mm_fault(struct vm_area_struct *vma,
            unsigned long address, enum fault_flags flags);







#endif /* !SEMINIX_MM_H */
